#include <iostream>
#include <fstream>
#include <vector>
#include <string.h>
#include <map>
#include <tinyxml.h>
#include <set>
#include <algorithm>

using namespace std;

struct match
{
  string team1;
  string team2;
  int result1;
  int result2;
  string url;
  string year;
};

set<int> empty;
map<string, set<int> > ind;

match read_match(TiXmlElement* p)
{
  match m{"", "", -1, -1, "", ""};
  TiXmlElement* pElem = p -> FirstChildElement();
  //cout << "First child: "  << pElem -> Value() << endl;
  while (NULL != pElem)
  {
    if (strcmp((char*)pElem -> Value(), "name1") == 0)
    {
      //cout << "Name1: " << pElem -> GetText() << endl;
      m.team1 = pElem -> GetText();
      //cout << "team1" << m.team1 << endl;
    }
    if (strcmp((char*)pElem -> Value(), "name2") == 0)
    {
      m.team2 = pElem -> GetText();
    }
    if (strcmp((char*)pElem -> Value(), "score") == 0)
    {
      char * pch1 = strtok((char*)(pElem -> GetText()), ":");
      m.result1 = atoi(pch1);
      char * pch2 = strtok(NULL, ":");
      m.result2 = atoi(pch2);
    }
    if (strcmp((char*)pElem -> Value(), "new") == 0)
    {
      m.url = pElem -> GetText();
      char* t2 = strtok((char*)pElem -> GetText(), "/");
      if (t2) {
        char* t3 = strtok(NULL, "/");
        if (t3) {
          m.year = t3;
          //cout << "year" << m.year << endl;
        }
        strtok(NULL, "/");
      }
    }
    pElem = pElem -> NextSiblingElement();
  }
  //cout << m.team1 << " " << m.team2 << " " << m.result1 << " " << m.result2 << " " << m.url << endl;
  return m;
}

set<int> search_in_index(string word)
{
  map <string, set<int> > :: iterator it = ind.find(word);
  if ( ind.end() != it )
  {
    set<int> team_matches = it -> second;
    /*for (set<int> :: iterator iter = team_matches.begin(); iter != team_matches.end(); ++iter)
    {
      cout << matches[*iter].result1 << endl;
    }*/
    return team_matches;
  }
  else
  {
    return empty;
  }
}


map<string, string> read_dictionary(string dict_name) //replacing termins from dict
{
  ifstream dict_stream; // reading dicts
  cout << "dict_name:" << dict_name << endl;
  dict_stream.open(dict_name.c_str());
  if (!(dict_stream.is_open()))
  {
    cout << "Error! Can't open dict file!" << endl;
  }
  string ss;
  map <string, string> synonyms;
  while (getline (dict_stream, ss)) //reading file string by string :)
  {
    char* pch;
    pch = strtok ((char*)ss.c_str(), "|"); //splitting strings into token
    char* pch2 = strtok (NULL, "|");
    if (!pch2) continue;
    synonyms[pch] = pch2; //adding to map
    //cout << "syn[" << pch << "]" << synonyms[pch] << endl;
  }
  dict_stream.close();
  return synonyms; 
}
  



  /*for (map <string, string> :: iterator i = synonyms.begin(); i != synonyms.end(); i++) {
      //элемент map'a - это пара(pair из <utility>), first - это индекс, second - значение
      cout << i -> first << ' ' << i -> second << endl;
   }*/

void syn_replace(vector<string>& query, vector<map<string, string> >& synonym_dicts) {
  for (int dict_idx = 0; dict_idx < synonym_dicts.size(); dict_idx++)  
  {
    map<string, string>& synonyms = synonym_dicts[dict_idx];
    for (int i = 0; i < query.size(); i++) //seaching words in dictionary
    {
      map <string, string> :: iterator it = synonyms.find(query[i]);
      if ( synonyms.end() != it )
      { 
        query[i] = synonyms[query[i]];
      }
      else if ((query[i][0] == '\"') && (query[i][query[i].size()-1] == '\"')) //deleting "
      {
        //out << qwords[i] << endl; 
        string cut; 
        cut.assign(query[i], 1, query[i].size()-2);

        //cout << cut << endl;

        it = synonyms.find(cut); //searching without "
        if (synonyms.end() != it)
        {
          query[i]= synonyms[cut];
        }
      }
      //out  << query[i] << endl;
    }
  }
}

vector<string> tokenize(char* str) {
  vector<string> result;
  while (str) {
    char* next_token = strtok(str, " ");
    result.push_back(str);
    str = next_token;
  }
  return result;
}

template<typename Iter>
string join(Iter begin, Iter end) {
  string result;
  for (Iter it = begin; it != end; ++it) {
    result += *it + " ";
  }
  result.erase(--result.end());
  return result;
}

int main (int argc, char** argv)
{
  vector<map<string, string> > synonym_dicts;  
  synonym_dicts.push_back(read_dictionary("./football_teams_stemmed.tsv")); //dicts
  synonym_dicts.push_back(read_dictionary("./hockey_teams_stemmed.tsv"));
  synonym_dicts.push_back(read_dictionary("./basketball_teams_stemmed.tsv"));
  synonym_dicts.push_back(read_dictionary("./volleyball_teams_stemmed.tsv"));
  cout << "Parsed synonyms" << endl;

  ifstream in;
  ofstream out;

  in.open(argv[1]); //reading query from 1st commline arg
  out.open("output.xml");

  string s;
  vector<string> qwords;
  while (in >> s)
  {
    qwords.push_back(s);
  }
  in.close();
  cout << "Unprocessed query: " << join(qwords.begin(), qwords.end()) << endl;
  syn_replace(qwords, synonym_dicts);
  cout << "Processed query: " << join(qwords.begin(), qwords.end()) << endl;
  
  //----------------------------------------------------------------------------------------------


  TiXmlDocument doc_("./xml1_stemmed.xml");
  doc_.LoadFile();
  if (doc_.Error())
  {
    cout << "Error! Can't open base file!" << endl;
  }
  else
  {
    cout << "File is open!" << endl;
  }
  TiXmlHandle hDoc(&doc_);
  TiXmlElement *pElem = hDoc.FirstChildElement().Element(); // узел
  if (pElem == NULL)
  {
    cout << "Error! File is not xml!" << endl;
  }
  TiXmlElement *pMatch = pElem -> FirstChildElement();
  vector<match> matches;
  //map<string, set<int> > index;
  int i = 0;
  while (NULL != pMatch)
  {
    match m = read_match(pMatch);    
    vector<string> teams;
    teams.push_back(m.team1);
    teams.push_back(m.team2);
    syn_replace(teams, synonym_dicts);
    m.team1 = teams[0];
    m.team2 = teams[1];

    //cout << m.team1 << " " << m.team2 << endl;
    
    matches.push_back(m);
    pMatch = pMatch -> NextSiblingElement();
    
    ind[m.team1].insert(i); 
    ind[m.team2].insert(i);
    if (!m.year.empty()) {
      ind[m.year].insert(i);
    }
    i++;
  }

  set<int> aggregated_result;

  //cout << "size " << qwords.size() << endl;
  for (int i = 0; i < qwords.size(); i++)
  {
    set<int> result = search_in_index(qwords[i]);
    if (result.empty())
      continue;
    if (aggregated_result.empty()) {
      aggregated_result = result;
    }
    vector<int> v(result.size());
    vector<int> :: iterator main_it;
    main_it = set_intersection (result.begin(), result.end(), aggregated_result.begin(), aggregated_result.end(), v.begin());
    aggregated_result.clear();
    aggregated_result.insert(v.begin(), main_it);
  }
  
   out << "<?xml version=\"1.0\" encoding=\"utf-8\"?> \n <!DOCTYPE event-set SYSTEM \"clschool.dtd\"> \n <event-set>" << endl;
  
  for (set<int>::iterator it = aggregated_result.begin(); it != aggregated_result.end(); ++it)
  {
    //cout << matches[*it].team1 << " " << matches[*it].team2 << " " << matches[*it].result1 << " " << matches[*it].result2 << endl;
    out << "<event id=\"1\" type=\"match\" title=\"матч " <<  matches[*it].team1 << "-" << matches[*it].team2 << "\" team1=\"" << matches[*it].team1<< "\" result1=\"" << matches[*it].result1 << "\" team2=\"" << matches[*it].team2 << "\" result2=\"" << matches[*it].result2 << "\" sport=\"football\" dateyear = \"" << matches[*it].year << "\" url=\"" << matches[*it].url << "\"> </event>" << endl;
  }
  out << "</event-set>" << endl;

  return 0;
}
